
With checks and asserts, you can set specific rules to ensure your data's
value falls within an acceptable range.

BAML provides two types of validations:
- **`@assert`** for strict validations. If a type fails an `@assert` validation, it
  will not be returned in the response. If the failing assertion was part of the
  top-level type, it will raise an exception. If it's part of a container, it
  will be removed from the container.
- **`@check`** for non-exception-raising validations. Whether a `@check` passes or
  fails, the data will be returned. You can access the results of invidividual
  checks in the response data.

## Assertions

Assertions are used to guarantee properties about a type or its components in a response.
They can be written directly as inline attributes next to the field
definition or on the line following the field definition, or on a top-level type used
in a function declaration.

### Using `@assert`

BAML will raise an exception if a function returns a `Foo` where `Foo.bar`
is not between 0 and 10.

If the function `NextInt8` returns `128`, BAML will raise an exception.

```baml BAML
class Foo {
  bar int @assert(between_0_and_10, {{ this > 0 and this < 10 }}) //this = Foo.bar value
}

function NextInt8(a: int) -> int @assert(ok_int8, {{ this >= -128 and this < 127 }}) {
  client GPT4
  prompt #"Return the number after {{ a }}"#
}
```

See [Jinja in Attributes](/ref/attributes/jinja-in-attributes) for a longer description of the Jinja syntax
available in asserts.

Asserts may be applied to a whole class via `@@assert`.

```baml BAML
class Bar {
  baz int
  quux string
  @@assert(length_limit, {{ this.quux|length < this.baz }})
}
```

### Using `@assert` with `Union` Types

Note that when using [`Unions`](/ref/baml/types#union-), it is
crucial to specify where the `@assert` attribute is applied within the union
type, as it is not known until runtime which type the value will be.

```baml BAML
class Foo {
  bar (int @assert(positive, {{ this > 0 }}) | bool @assert(is_true, {{ this }}))
}
```

In the above example, the `@assert` attribute is applied specifically to the
`int` and `string` instances of the `Union`, rather than to the `Foo.bar` field
as a whole.

Likewise, the keyword `this` refers to the value of the type instance it is
directly associated with (e.g., `int` or `string`).

## Chaining Assertions
You can have multiple assertions on a single field by chaining multiple `@assert` attributes.

In this example, the asserts on `bar` and `baz` are equivalent.
```baml BAML
class Foo {
  bar int @assert(between_0_and_10, {{ this > 0 and this < 10 }})
  baz int @assert(positive, {{ this > 0 }}) @assert(less_than_10, {{ this < 10 }})
}
```

Chained asserts are evaluated in order from left to right. If the first assert
fails, the second assert will not be evaluated.

## Writing Assertions

Assertions are represented as Jinja expressions and can be used to validate
various types of data. Possible constraints include checking the length of a
string, comparing two values, or verifying the presence of a substring with
regular expressions.

In the future, we plan to support shorthand syntax for common assertions to make
writing them easier.

For now, see our [Jinja cookbook / guide](/ref/prompt-syntax/what-is-jinja)
or the [Minijinja filters docs](https://docs.rs/minijinja/latest/minijinja/filters/index.html#functions)
for more information on writing expressions.



### Expression keywords

- `this` refers to the value of the current field being validated.


`this.field` is used to refer to a specific field within the context of `this`.
Access nested fields of a data type by chaining the field names together with a `.` as shown below.
```baml BAML
class Resume {
  name string
  experience string[]

}

class Person {
  resume Resume @assert({{ this.experience|length > 0 }}, "Nonzero experience")
  person_name name
}
```

## Assertion Errors

When asserts fail, your BAML function will raise a `BamlValidationError`
exception, same as when parsing fails. You can catch this exception and handle
it as you see fit.

You can define custom names for each assertion, which will be included
in the exception for that failure case. If you don't define a custom name,
BAML will display the body of the assert expression.

In this example, if the `quote` field is empty, BAML raises a
`BamlValidationError` with the message **"exact_citation_not_found"**. If the
`website_link` field does not contain **"https://",** it raises a
`BamlValidationError` with the message **invalid_link**.

```baml BAML
class Citation {
  //@assert(<name>, <expr>)
  quote string @assert(exact_citation_found,
	  {{ this|length > 0 }}
  )

  website_link string @assert(valid_link,
    {{ this|regex_match("https://") }}
  )
}
```

<Tabs>
<Tab title="Python" language="python">
```python
from baml_client import b
from baml_client.types import Citation

def main():
    try:
        citation: Citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...")

        # Access the value of the quote field
        quote = citation.quote
        website_link = citation.website_link
        print(f"Quote: {quote} from {website_link}")
        
    except BamlValidationError as e:
        print(f"Validation error: {str(e)}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
```
</Tab>

<Tab title="TypeScript" language="typescript">
```typescript
import { b, BamlValidationError } from './baml_client';
import { Citation } from './baml_client/types';

const main = () => {
    try {
        const citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...");
        
        const quote = citation.quote.value;
        console.log(`Quote: ${quote}`);

        const checks = citation.quote.checks;
        console.log(`Check exact_citation_found: ${checks.exact_citation_found.status}`);
        for (const check of get_checks(checks)) {
            console.log(`Check ${check.name}: ${check.status}`);
        }

        const author = citation.author;
        console.log(`Author: ${author}`);
    } catch (e) {
        if (e instanceof BamlValidationError) {
            console.log(`Validation error: ${e}`);
        } else {
            console.error(e);
        }
    }
};
```
</Tab>

<Tab title="Go" language="go">
```go
package main

import (
    "context"
    "fmt"
    
    "github.com/boundaryml/baml"
)

func main() {
    ctx := context.Background()
    
    citation, err := baml.GetCitation(ctx, "SpaceX, is an American spacecraft manufacturer, launch service provider...", nil)
    if err != nil {
        // Handle validation errors
        if validationErr, ok := err.(*baml.ValidationError); ok {
            fmt.Printf("Validation error: %v\n", validationErr)
            return
        }
        fmt.Printf("An unexpected error occurred: %v\n", err)
        return
    }
    
    // Access the citation fields
    fmt.Printf("Quote: %s from %s\n", citation.Quote, citation.WebsiteLink)
}
```
</Tab>
</Tabs>


## Checks

`@check` attributes add validation without raising exceptions if they fail.
Types with `@check` attributes allow the checks to be inspected at
runtime.


```baml BAML
type Bar = ( bar int @check(less_than_zero, {{ this < 0 }}) )[]
```

<Tabs>
<Tab title="Python" language="python">
```python
Bar = List[Checked[int, Dict[Literal["less_than_zero"]]]]
```
</Tab>

<Tab title="TypeScript" language="typescript">
```typescript
type Bar = Checked<int,"less_than_zero">[]
```
</Tab>

<Tab title="Go" language="go">
```go
// Go type signature for checked fields:
type Bar = []baml.Checked[int, map[string]baml.CheckResult]
// where the map contains "less_than_zero" as a key
```
</Tab>
</Tabs>


The following example uses both `@check` and `@assert`. If `line_number` fails its
`@assert`, no `Citation` will be returned by `GetCitation()`. However,
`exact_citation_not_found` can fail without interrupting the result. Because it
was a `@check`, client code can inspect the result of the check.


```baml BAML
class Citation {
  quote string @check(
      exact_citation_match,
	  {{ this|length > 0 }}
  )
  line_number string @assert(
    has_line_number,
    {{ this|length >= 0 }}
  )
}

function GetCitation(full_text: string) -> Citation {
  client GPT4 
  prompt #"
    Generate a citation of the text below in MLA format:
    {{full_text}}

    {{ctx.output_format}}
  "#
}

```

<Tabs>
<Tab title="Python" language="python">
```python
from baml_client import b
from baml_client.types import Citation, get_checks

def main():
    citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...")

    # Access the value of the quote field
    quote = citation.quote.value 
    print(f"Quote: {quote}")

    # Access a particular check.
    quote_match_check = citation.quote.checks['exact_citation_match'].status
    print(f"Citation match status: {quote_match_check})")

    # Access each check and its status.
    for check in get_checks(citation.quote.checks):
        print(f"Check {check.name}: {check.status}")
```
</Tab>

<Tab title="TypeScript" language="typescript">
```typescript
import { b, get_checks } from './baml_client'
import { Citation } from './baml_client/types'

const main = () => {
    const citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...");

    // Access the value of the quote field
    const quote = citation.quote.value
    console.log(`Quote: ${quote}`)

    // Access a particular check.
    const quote_match_check = citation.quote.checks.exact_citation_match.status;
    console.log(`Exact citation status: ${quote_match_check}`);

    // Access each check and its status.
    for (const check of get_checks(citation.quote.checks)) {
        console.log(`Check: ${check.name}, Status: ${check.status}`)
    }
}
```
</Tab>

<Tab title="Go" language="go">
```go
package main

import (
    "context"
    "fmt"
    
    "github.com/boundaryml/baml"
)

func main() {
    ctx := context.Background()
    
    citation, err := baml.GetCitation(ctx, "SpaceX, is an American spacecraft manufacturer, launch service provider...", nil)
    if err != nil {
        panic(fmt.Sprintf("Failed to get citation: %v", err))
    }
    
    // Access the value of the quote field
    quote := citation.Quote.Value
    fmt.Printf("Quote: %s\n", quote)
    
    // Access a particular check
    exactCitationMatch := citation.Quote.Checks["exact_citation_match"].Status
    fmt.Printf("Citation match status: %s\n", exactCitationMatch)
    
    // Access each check and its status
    for name, check := range citation.Quote.Checks {
        fmt.Printf("Check %s: %s\n", name, check.Status)
    }
}
```
</Tab>
</Tabs>

You can also chain multiple `@check` and `@assert` attributes on a single field.

```baml BAML
class Foo {
  bar string @check(bar_nonempty, {{ this|length > 0 }})
  @assert(bar_no_foo, {{ this|regex_match("foo") }})
  @check(bar_no_fizzle, {{ this|regex_match("fizzle") }})
  @assert(bar_no_baz, {{ this|regex_match("baz") }})
}
```

<Tip> When using `@check`, all checks on the response data are evaluated even if
one fails. In contrast, with `@assert`, a failure will stop the parsing process
and immediately raise an exception. </Tip>


## Advanced Example

The following example shows more complex minijinja expressions, see the
[Minijinja filters docs](https://docs.rs/minijinja/latest/minijinja/filters/index.html#functions)
for more information on available operators to use in your assertions.

--------

The `Book` and `Library` classes below demonstrate how to validate a book's
title, author, ISBN, publication year, genres, and a library's name and books.
The block-level assertion in the `Library` class ensures that all books have
unique ISBNs.

```baml BAML
class Book {
    title string @assert(this|length > 0)
    author string @assert(this|length > 0)
    isbn string @assert(
        {{ this|regex_match("^(97(8|9))?\d{9}(\d|X)$") }},
        "Invalid ISBN format"
    )
    publication_year int @assert(valid_pub_year, {{ 1000 <= this <= 2100 }})
    genres string[] @assert(valid_length, {{ 1 <= this|length <= 10 }})
}

class Library {
    name string
    books Book[] @assert(nonempty_books, {{ this|length > 0 }})
                 @assert(unique_isbn, {{ this|map(attribute='isbn')|unique()|length == this|length }} )
}
```

In this example, we use a block-level `@@assert` to check a dependency across
a pair of fields.

```baml BAML
class Person {
    name string @assert(valid_name, {{ this|length >= 2 }})
    age int @assert(valid_age, {{ this >= 0 }})
    address Address

    @@assert(not_usa_minor, {{
        this.age >= 18 or this.address.country != "USA",
    }})
}

```
